﻿using System;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Service.Template;
using Me.Prettyprint.Hector.Api;
using Me.Prettyprint.Hector.Api.Beans;
using Me.Prettyprint.Hector.Api.Query;

namespace Me.Prettyprint.Cassandra.Service
{
    public class SliceCounterFinish<N>
    {
        public SliceCounterFinish(N defaultn)
        {
            Finish = defaultn;
        }
        public N Finish
        {
            get;
            set;
        }
        public N Function()
        {
            return Finish;
        }
    }
    public class CounterColumnEnumerator<N>
    {
        public CounterColumnEnumerator(List<HCounterColumn<N>> column)
        {
            Columns = column;
        }
        public List<HCounterColumn<N>> Columns
        {
            get;
            set;
        }
        protected int Position
        {
            get;
            set;
        }
        public bool HasNext()
        {
            return Columns.Count > Position;
        }
        public HCounterColumn<N> Next()
        {
            Position++;
            return Columns[Position];
        }
        public void Reset()
        {
            Position = 0;
        }
    }
    public class SliceCounterEnumerator<K, N, V> : IEnumerator<HCounterColumn<N>>
    {
        private const int DEFAULT_COUNT = 100;

        #region Constructors
        public SliceCounterEnumerator(SliceCounterQuery<K, N> query, N start, N finish, bool reversed)
            : this(query, start, finish, reversed, DEFAULT_COUNT)
        {
        }
        public SliceCounterEnumerator(SliceCounterQuery<K, N> query, N start, N finish, bool reversed, int count)
            : this(query, start, new SliceCounterFinish<N>(finish), reversed, count)
        {
        }
        public SliceCounterEnumerator(SliceCounterQuery<K, N> query, N start, SliceCounterFinish<N> finish, bool reversed)
            : this(query, start, finish, reversed, DEFAULT_COUNT)
        {
        }
        public SliceCounterEnumerator(SliceCounterQuery<K, N> query, N start, SliceCounterFinish<N> finish, bool reversed, int count)
        {
            Query = query;
            Start = start;
            Finish = finish;
            Reversed = reversed;
            Count = count;
            Query.SetRange(Start, Finish.Function(), Reversed, Count);
        }
        #endregion
        private SliceCounterQuery<K, N> Query
        {
            get;
            set;
        }
        private N Start
        {
            get;
            set;
        }
        private SliceCounterFinish<N> Finish
        {
            get;
            set;
        }
        private SliceFilter<HCounterColumn<N>> Filter
        {
            get;
            set;
        }
        private bool Reversed
        {
            get;
            set;
        }
        private int Count
        {
            get;
            set;
        }
        private int Columns
        {
            get;
            set;
        }
        private CounterColumnEnumerator<N> Enumerator
        {
            get;
            set;
        }
        public SliceCounterEnumerator<K,N,V> SetFilter(SliceFilter<HCounterColumn<N>> filter)
        {
            Filter = filter;
            return this;
        }
        protected HCounterColumn<N> CurrentObject
        {
            get;
            set;
        }
        public bool MoveNext()
        {
            bool has = HasNext();
            if (has)
            {
                Next();
            }
            return has;
        }
        public void Reset()
        {
            Enumerator.Reset();
        }
        public void Dispose()
        {
            Enumerator = null;
            Query = null;
        }
        public HCounterColumn<N> Current
        {
            get { return CurrentObject; }
        }
        object System.Collections.IEnumerator.Current
        {
            get { return this.Current; }
        }
        public bool HasNext()
        {
            if (Enumerator == null)
            {
                Enumerator = new CounterColumnEnumerator<N>(Query.Execute().Get().Columns);
            }
            else if (!Enumerator.HasNext() && Columns == Count)
            {  // only need to do another query if maximum columns were retrieved
                Refresh();
            }

            while (Filter != null && Enumerator != null && Enumerator.HasNext() && !Filter.Accept(Enumerator.Next()))
            {
                Next();

                if (!Enumerator.HasNext() && Columns == Count)
                {
                    Refresh();
                }
            }

            return Enumerator.HasNext();
        }
        private void Refresh()
        {
            Query.SetRange(Start, Finish.Function(), Reversed, Count);
            Columns = 0;
            List<HCounterColumn<N>> list = Query.Execute().Get().Columns;
            Enumerator = new CounterColumnEnumerator<N>(list);

            if (Enumerator.HasNext())
            {
                // The lower bound column may have been removed prior to the query executing,
                // so check to see if the first column returned by the current query is the same
                // as the lower bound column.  If both columns are the same, skip the column
                N first = list[0].GetName();
                if (first.Equals(Start))
                {
                    Next();
                }
            }
        }
        public HCounterColumn<N> Next()
        {
            CurrentObject = Enumerator.Next();
            Start = CurrentObject.GetName();
            Columns++;
            return CurrentObject;
        }
    }
}
